<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			html,body{
				width: 100%;
				height: 100%;
			}
			#myCanvas{
				border: 1px solid #f40;
				margin: 10px;
				mix-blend-mode: screen;
				position: relative;
				z-index: 1;
			}
		</style>
	</head>
	<body>
		<canvas id="myCanvas" width="400" height="400"></canvas>
		<script type="text/javascript">
			// 本类已收纳至自制 js 库内
			class SlowMove {
				animationList = []
				start = []
				curr = []
				timer = null
				running = false
				num = 1
				dim = 1
				speed = 3 // 0 ~ 10
				constructor(options) {
				    this.init(options)
				}
				init(options){
					Object.assign(this,options)
					this.dim = this.num
					for(let i=0; i<this.dim; i++){
						this.curr[i] = 0
						if(this.start[i]){
							this.curr[i] = this.start[i]
						}
					}
				}
				move(...args){
					var m = () => {
						if(!this.timer){
							this.running = true
							let end = this.animationList.shift()
							let step = []
							this.timer = setInterval(()=>{
								let stop = true
								for(let i=0; i<this.dim; i++){
									step[i] = (end[i] - this.curr[i]) * this.speed / 20
									this.curr[i] += step[i]
									if(Math.abs(step[i]) > .1){
										stop = false
									}
								}
								this.handler(this.curr)
								if(stop){
									clearInterval(this.timer)
									this.timer = null
									this.stepFinish()
									if(this.animationList.length !== 0){
										this.curr = end
										m()
									}else{
										this.running = false
										this.allFinish()
									}
								}
							},16)
						}
					}
					this.animationList.push(args)
					m()
				}
				// hooks
				handler(){}
				stepFinish(){}
				allFinish(){}
			}
		</script>
		<script type="text/javascript">
			!function(w,e){
				function Game(option){
					Object.assign(this,{
						el: "#myCanvas",
						mainWidth: 400,
						timer: null,
						pos: [0,0],
						axis: [0,0],
						side: 100,
						nX: 4,
						nY: 4,
						slideList: [],
					},option)
					this.init()
				}
				Game.prototype.expend = function(obj){Object.assign(this,obj)}
				Game.prototype.expend({
					
					// ********************  基础底层部分
					
					init(){
						this.canvas = e.querySelector(this.el)
						this.canvas.isUsed = true
						this.canvas.setAttribute("width",this.side*this.nX)
						this.canvas.setAttribute("height",this.side*this.nY)
						this.cx = this.canvas.getContext("2d")
						this.sm = new SlowMove({
							speed: 6, // 动画速度
							num: 2, // 要处理的动画个数, 默认是 1
							start: [0,0], // 开始值, 请务必与参数个数配置保持一致
							handler: data => { // 动画进行过程中每一帧都会执行，通过 data 参数获取当前所有关键帧插值组成的数组
								this.pos[0] = data[0]
								this.pos[1] = data[1]
							},
							stepFinish(){
								console.log("step is finish")
							},
							allFinish(){
								console.log("All animations are finished")
							}
						})
						console.log(this.sm)
						this.addEvents()
						this.start()
					},
					addEvents(){
						this.windowKeydown = evt => {
							var k = evt.key
							if(k === "a" || k === "A" || k === "ArrowLeft"){
								this.slide(3)
							}else if(k === "d" || k === "D" || k === "ArrowRight"){
								this.slide(1)
							}else if(k === "w" || k === "W" || k === "ArrowUp"){
								this.slide(0)
							}else if(k === "s" || k === "S" || k === "ArrowDown"){
								this.slide(2)
							}
						}
						e.addEventListener("keydown",this.windowKeydown)
					},
					start(){
						this.cx.fillStyle = "#99f"
						this.draw(()=>{
							this.cx.fillRect(this.pos[0],this.pos[1],100,100)
						})
					},
					draw(frame){
						this.timer && clearInterval(this.timer)
						this.timer = setInterval(() => {
							this.cx.save()
							this.cx.clearRect(0,0,this.mainWidth,this.mainWidth)
							frame()
							this.cx.restore()
						},16)
					},
					destroy(){
						this.timer && clearInterval(this.timer)
						this.cTimer && clearInterval(this.cTimer)
						this.canvas.isUsed = false
						w.removeEventListener("keydown",this.windowKeydown)
					},
					
					// ********************  操作逻辑部分
					
					slide(direction){
						if(direction === 0){
							if(this.axis[1] > 0){
								this.slowMove(this.axis[0],--this.axis[1])
							}
						}else if(direction === 1){
							if(this.axis[0] < this.nX - 1){
								this.slowMove(++this.axis[0],this.axis[1])
							}
						}else if(direction === 2){
							if(this.axis[1] < this.nY - 1){
								this.slowMove(this.axis[0],++this.axis[1])
							}
						}else{
							if(this.axis[0] > 0){
								this.slowMove(--this.axis[0],this.axis[1])
							}
						}
					},
					slowMove(...args){
						this.sm.move(args[0]*this.side,args[1]*this.side)
					}
				})
				w.Game = Game
			}(window,document)
			var gameDemo = new Game()
			
			
			
		</script>
	</body>
</html>